home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Utilities / Converters / Convert_TEXT / Source / CharController.m < prev    next >
Text File  |  1995-06-12  |  18KB  |  475 lines

  1. /***********************************************************************
  2. Controller class for Convert TEXT which converts between Mac and NeXT text.
  3. Copyright (C) 1993 David John Burrowes
  4.  
  5. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version.
  6.  
  7. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
  8.  
  9. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  10.  
  11. The author, David John Burrowes, can be reached at:
  12.     davidjohn@kira.net.netcom.com
  13.     David John Burrowes
  14.     1926 Ivy #10
  15.     San Mateo, CA 94403-1367
  16. ***********************************************************************/
  17.  
  18. #import "CharController.h"
  19. #import "NeXTToMacText.h"
  20. #import "MacToNeXTText.h"
  21. #import "CRLFToNeXTText.h"
  22. #import "NeXTToCRLFText.h"
  23. #import "File.h"
  24. #import <appkit/Cell.h>
  25. #import <appkit/Matrix.h>
  26.  
  27. @implementation CharController
  28.  
  29.  
  30.  
  31. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  32. //    Routine:        init
  33. //    Parameters:    none
  34. //    Returns:        self
  35. //    Stores:        none
  36. //    Description:
  37. //        This overrides the defalut init method.  But it does little else.
  38. //        Other initializations done in AppDidInit, above...
  39. //        Note that subclasses should OVERRIDE this 
  40. //    Bugs:
  41. //    History:
  42. //    93.07.05    djb    Reworked conversion preferences.  Used tobe a boolean for yes or no
  43. //                to indicate mac vs. next source conversion.  Now use a string to
  44. //                indicate what kinda conversion should be default.  Non-intuitively,
  45. //                I've decided to leave the default name the same (DoMacConversio)
  46. //                and let it keep the old yes/no, as well as newer MacToNeXT, etc
  47. //                options.  Icky, but provides some upward compat..  HOWEVER.
  48. //                This has taught me, I think, the lesson that: defaults names should
  49. //                be a bit general, and it's better if their options are meaningful rather
  50. //                than booleans.  Both allow later changes without breaking things like
  51. //                this.
  52. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  53. - init
  54. {
  55.     //
  56.     //    Get all the default values from the database
  57.     //
  58.     static NXDefaultsVector theDefaults =
  59.     {
  60.         {"UseCurlyQuotes", "NO"},
  61.         {"UseIMv1", "NO"},
  62.         {"DoMacConversion", "MacToNeXT"},
  63.         {NULL, NULL}
  64.     };
  65.     CString    tempPreference;
  66.     
  67.     [super init];
  68.     //
  69.     //    Set up strings for the interface.
  70.     //
  71.     ConversionString = "Converting text files";
  72.     SourcePrompt = "Source file:";
  73.     DestPrompt = "Dest file:";
  74.     DestExtension = "";
  75.     DefaultsOwner = "MacToNeXTText";
  76.  
  77.     NXRegisterDefaults(DefaultsOwner, theDefaults);
  78.     
  79.     //
  80.     //    Note that we completely ignore the old DoMacConversion preference.
  81.     //    We neither read nor remove it.
  82.     //
  83.  
  84.     UseCurlyQuotes = [self   GetBoolPref: "UseCurlyQuotes"];
  85.  
  86.     UseIMv1 = [self   GetBoolPref: "UseIMv1"];
  87.     
  88.     tempPreference = [self   GetPref: "DoMacConversion"];
  89.     //
  90.     //    New for 1.1.  Get a more detailed conversion type from the defaults database,
  91.     //    and set our new ConversionType flag appropriately.
  92.     //
  93.     if ((strcmp(tempPreference, "MacToNeXT") == 0) ||
  94.         (strcmp(tempPreference, "YES") == 0) )
  95.         DefaultConversion = MacToNeXT;
  96.     else if ((strcmp(tempPreference, "NeXTToMac") == 0) ||
  97.         (strcmp(tempPreference, "NO") == 0) )
  98.         DefaultConversion = NeXTToMac;
  99.     else if (strcmp(tempPreference, "CRLFToNeXT") == 0)
  100.         DefaultConversion = CRLFToNeXT;
  101.     else if (strcmp(tempPreference, "NeXTToCRLF") == 0)
  102.         DefaultConversion = NeXTToCRLF;
  103.  
  104.     //
  105.     //    Since we are pretending to be a converter as well as controller, define our manager
  106.     //    And, then set ourselves up to recieve the messages we sent to a converter!
  107.     //
  108.     myManager = NullInstance;
  109.  
  110.     converterInst = self;
  111.     //
  112.     //    Set up default converter.
  113.     //
  114.     theConverter = NullInstance;
  115.     CurrentConversion = DefaultConversion;
  116.  
  117.     return self;
  118. }
  119.  
  120. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  121. //    Routine:        displayPreferences: 
  122. //    Parameters:    the object that called us
  123. //    Returns:        self
  124. //    Stores:        none
  125. //    Description:
  126. //        This is called whenever we need to bring the preferences panel onto the screen.
  127. //        Using the value in our internal preference variables, then we set the buttons
  128. //        in the preference panel to reflect these, and then we show the panel.
  129. //    History:
  130. //        93.07.05    djb    Modified for 1.1's more complex default conversion choices.
  131. //    Bugs:
  132. //        Well, strictly speaking, this is only needed the first time this is called,
  133. //        because thereafter the buttons maintain their own highlite properly.
  134. //        Oh well.  This whole scheme is a bit awkward, given my trivial use, and the fact
  135. //        that it really seems to be designed for bigger things.
  136. //        This doesn't set any ResultObject fields. =(
  137. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  138. -displayPreferences: sender
  139. {
  140.     //
  141.     //    Get the default preference values, and compare judge what buttons to
  142.     //    highlight for the user.
  143.     //
  144.     if (UseIMv1 == YES)
  145.         [UseIMv1Button  setIntValue: 1];
  146.     else
  147.         [UseIMv1Button  setIntValue: 0];
  148.         
  149.     if (UseCurlyQuotes == YES)
  150.         [UseCurlyQuotesButton  setIntValue: 1];
  151.     else
  152.         [UseCurlyQuotesButton  setIntValue: 0];
  153.  
  154.     switch (DefaultConversion)
  155.     {
  156.         case MacToNeXT:
  157.             [DefaultConversionButton  selectCellWithTag: MacToNeXT];
  158.             break;
  159.         case NeXTToMac: 
  160.             [DefaultConversionButton  selectCellWithTag: NeXTToMac];
  161.             break;
  162.         case CRLFToNeXT:
  163.             [DefaultConversionButton  selectCellWithTag: CRLFToNeXT];
  164.             break;
  165.         case NeXTToCRLF:
  166.             [DefaultConversionButton  selectCellWithTag: NeXTToCRLF];
  167.             break;
  168.     }
  169.  
  170.     [prefPanel    makeKeyAndOrderFront:self];
  171.     //
  172.     return self;
  173. }
  174.  
  175.  
  176. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  177. //    Routine: SetIMV1: 
  178. //    Parameters: the object that called us
  179. //    Returns:        self
  180. //    Stores:        nothing!
  181. //    Description:
  182. //        This method gets called whenever the user clicks on a button to change
  183. //        the setting of whether we should use IMv1 when converting Mac files.
  184. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  185. - SetIMV1: sender
  186. {
  187.     if ( [sender intValue]  == 1)
  188.         UseIMv1 = YES;
  189.     else
  190.         UseIMv1 = NO;
  191.  
  192.     [self   SetBoolPref: "UseIMv1" To: UseIMv1];
  193.  
  194.     return self;
  195. }
  196.  
  197.  
  198. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  199. //    Routine:        SetUseCurlyQuotes: 
  200. //    Parameters:    the object that called us
  201. //    Returns:        self
  202. //    Stores:        nothing!
  203. //    Description:
  204. //        This method gets called whenever the user clicks on a button to change
  205. //        the setting of whether we should convert to curly quotes when converting NeXT files.
  206. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  207. -SetUseCurlyQuotes: sender
  208. {
  209.     if ( [sender intValue]  == 1)
  210.         UseCurlyQuotes = YES;
  211.     else
  212.         UseCurlyQuotes = NO;
  213.  
  214.     [self   SetBoolPref: "UseCurlyQuotes" To: UseCurlyQuotes];
  215.  
  216.     return self;
  217. }
  218.  
  219.  
  220. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  221. //    Routine:        SetDefaultConversion: 
  222. //    Parameters:    the object that called us
  223. //    Returns:        self
  224. //    Stores:        nothing!
  225. //    Description:
  226. //        This method gets called whenever the user clicks on a button to change
  227. //        the setting of whether we should assume files to be converted are Mac ones or not.
  228. //    History:
  229. //        93.07.05    djb    Modified for 1.1's richer conversion options.  NOTE: This
  230. //                    makes some assumptions that the sender's value will always be
  231. //                    one of it's conversionvalues.
  232. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  233. -SetDefaultConversion: sender
  234. {
  235.     DefaultConversion =  [[sender selectedCell] tag] ;
  236.     
  237.     switch ( DefaultConversion )
  238.     {
  239.         case MacToNeXT:
  240.             [self   SetPref: "DoMacConversion" To: "MacToNeXT"];
  241.             break;
  242.         case NeXTToMac: 
  243.             [self   SetPref: "DoMacConversion" To: "NeXTToMac"];
  244.             break;
  245.         case CRLFToNeXT:
  246.             [self   SetPref: "DoMacConversion" To: "CRLFToNeXT"];
  247.             break;
  248.         case NeXTToCRLF:
  249.             [self   SetPref: "DoMacConversion" To: "NeXTToCRLF"];
  250.             break;
  251.     }
  252.  
  253.     CurrentConversion = DefaultConversion;
  254.  
  255.     return self;
  256. }
  257.  
  258.  
  259.  
  260. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  261. //    Method:        PrepareToConvertMac 
  262. //    Parameters:    the object that send this message
  263. //    Returns:        self
  264. //    Stores:        nothing
  265. //    Description:
  266. //        Sets the flag for the kind of conversion to do (not a mac one), and convert a file.
  267. //    Bugs:
  268. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  269. - PrepareToConvertMac:sender
  270. {
  271.     CurrentConversion = MacToNeXT;
  272.     [self  PrepareForConversion: self];
  273.     return self;
  274. }
  275.  
  276. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  277. //    Method:        PrepareToConvertNeXT 
  278. //    Parameters:    the object that send this message
  279. //    Returns:        self
  280. //    Stores:        nothing
  281. //    Description:
  282. //        Sets the flag for the kind of conversion to do (not a mac one), and convert a file.
  283. //    Bugs:
  284. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  285. - PrepareToConvertNeXT:sender
  286. {
  287.     CurrentConversion = NeXTToMac;
  288.     [self     PrepareForConversion: self];
  289.     return self;
  290. }
  291.  
  292.  
  293. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  294. //    Method:        PrepareToConvertCRLF 
  295. //    Parameters:    the object that send this message
  296. //    Returns:        self
  297. //    Stores:        nothing
  298. //    Description:
  299. //        Sets the flag for the kind of conversion to do (CRLF to NeXT) and does the
  300. //        conversion.  We set the CurrentConversion flag here to override the default
  301. //        value it would have..
  302. //    Bugs:
  303. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  304. - PrepareToConvertCRLF:sender
  305. {
  306.     CurrentConversion = CRLFToNeXT;
  307.     [self     PrepareForConversion: self];
  308.     return self;
  309. }
  310.  
  311. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  312. //    Method:        PrepareToConvertNeXTToCRLF
  313. //    Parameters:    the object that send this message
  314. //    Returns:        self
  315. //    Stores:        nothing
  316. //    Description:
  317. //        Sets the flag for the kind of conversion to do (NeXT to CRLF) and does the
  318. //        conversion.  We set the CurrentConversion flag here to override the default
  319. //        value it would have..
  320. //    Bugs:
  321. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  322. - PrepareToConvertNeXTToCRLF:sender
  323. {
  324.     CurrentConversion = CRLFToNeXT;
  325.     [self     PrepareForConversion: self];
  326.     return self;
  327. }
  328.  
  329.  
  330.  
  331. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  332. //    Method:        ReportTo:
  333. //    Parameters:    The caller
  334. //    Returns:     none
  335. //    Stores:        none
  336. //    Description:
  337. //        ConvertController's use this to tell the converter what object to report status
  338. //        to.  That is, we must tell sender when we are, for example, 50% of the way
  339. //        done so it can let the user know what's going on.  Subclasses should have no
  340. //        need of subclassing this.  It will always be set up before a call to the main
  341. //        conversion routine.
  342. //    Bugs:
  343. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  344. - ReportTo: sender
  345. {
  346.     myManager = sender;
  347.     return self;
  348. }
  349.  
  350.  
  351. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  352. //    Method:        isThisAGoodFile:
  353. //    Parameters:    A File instance
  354. //    Returns:     YES if it is, NO if it isn't.
  355. //    Stores:        none
  356. //    Description:
  357. //        A converter, in addition to converting a file X to a file Y, should be able to
  358. //        identify when a source file is a legitimate file for conversion.  In the case of
  359. //        this abstract class, this method does nothing.  A subclass, however, will
  360. //        subclass this method and have it examine the specified file, and determine
  361. //        if it's a legit file or not.  It returns YES if the file is good, or NO if the file is
  362. //        questionable or bad.  
  363. //    Bugs:
  364. //        We need to use the proposed Fact datatype here, instead of Boolean.
  365. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  366. - (Boolean) isThisAGoodFile: Instance
  367. {
  368.     return YES;
  369. }
  370.  
  371.  
  372.  
  373.  
  374. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  375. //    Routine:        ConvertFrom:To: 
  376. //    Parameters:    The file to be converted from, and the file to be converted to
  377. //    Returns:        self
  378. //    Stores:        error code
  379. //    Description:
  380. //        This uses the object stored in this object's instance variable theConverter
  381. //        to convert the contents of the source file to a new form, and writes them out
  382. //        into the destination file.  Note that this assumes that the converter is a subclass
  383. //        of textConverter.  Basiclally, loop until we find the eof, readin 512 byte chunks,
  384. //        converting, and writing out.  In the last time through, we find Eof, and
  385. //        write out what we read in that was just before this eof, then quit when we
  386. //        loop around.
  387. //    History:
  388. //        93.07.05    djb    Modified for the now 4 types of conversions, rather than the older 2.
  389. //    Bugs
  390. //        We ignore errors that the file access might generate.
  391. //        (if we don't read 512 bytes, and we don't find eof, then we have an error.
  392. //        but we don't check for it either )
  393. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  394. - ConvertFrom: sourceFile To: destinationFile
  395. {
  396.     Pointer            sourceBuffer        = NewPointer(512);
  397.     Pointer            destinationBuffer;
  398.     PositiveInteger    numWritten,
  399.                     bytesRead        = 512;
  400.     Boolean            eofFound            = NO;
  401.     Real                modifier        =  100.0 / [sourceFile   FileSize];
  402.  
  403.     [super   ConvertFrom: sourceFile To: destinationFile];
  404.  
  405.     [MacConvertCommand    setEnabled: NO];
  406.     [NextConvertCommand    setEnabled: NO];
  407.     [CRLFConvertCommand    setEnabled: NO];
  408.     [NeXT2CRLFConvertCommand    setEnabled: NO];
  409.     [ConvertCommands    setEnabled: NO];
  410.     //
  411.     //    Kill any converter waiting around, then set up the proper one for this conversion.
  412.     //
  413.     if (theConverter != NullInstance)
  414.         [theConverter   free];
  415.  
  416.     switch ( CurrentConversion )
  417.     {
  418.         case MacToNeXT:
  419.             theConverter = [ [MacToNeXTText  alloc] init ];
  420.             [theConverter  UseIM1: UseIMv1];
  421.             ConversionString = "Converting Macintosh text to NeXT text";
  422.             break;
  423.         case NeXTToMac: 
  424.             theConverter = [[NeXTToMacText alloc] init];
  425.             [theConverter ConvertSingleQuotes: UseCurlyQuotes];
  426.             ConversionString = "Converting NeXT text to Macintosh text";
  427.             break;
  428.         case CRLFToNeXT:
  429.             theConverter = [ [CRLFToNeXTText  alloc] init ];
  430.             ConversionString = "Converting CRLF text to NeXT text";
  431.             break;
  432.         case NeXTToCRLF:
  433.             theConverter = [ [NeXTToCRLFText  alloc] init ];
  434.             ConversionString = "Converting NeXT text to CRLF text";
  435.             break;
  436.     }
  437.     //
  438.     //    With the converter set up, set the flag so it will do the default conversion
  439.     //    (stored in DoMacConversion) next time if none other is specified.
  440.     //    (that is, if someone drags a file onto our window, do the default conversion,
  441.     //    and not the one we are actually about to do).
  442.     //
  443.     CurrentConversion = DefaultConversion;
  444.  
  445.  
  446.     [super   ConvertFrom: sourceFile To: destinationFile];
  447.  
  448.     while ((eofFound != YES) && (bytesRead == 512))
  449.     {
  450.         [sourceFile    Read: 512 BytesInto: sourceBuffer];
  451.         bytesRead = [sourceFile   GetPositiveInteger];
  452.         eofFound = [sourceFile   GetBooleanFrom: SECOND_RESULT];
  453.         //
  454.         //    If eof was found, then this is our last pass through the converter.
  455.         //
  456.         [theConverter    ConvertString: sourceBuffer WithLength: bytesRead];
  457.         destinationBuffer = [theConverter    GetPointer];
  458.         numWritten = [theConverter   GetPositiveIntegerFrom: SECOND_RESULT];
  459.         [destinationFile    Write:  numWritten  BytesFrom: destinationBuffer];
  460.         [myManager   SetPercentageDone: modifier * [sourceFile  GetCurrentPosition]];
  461.     }
  462.     [MacConvertCommand    setEnabled: YES];
  463.     [NextConvertCommand    setEnabled: YES];
  464.     [CRLFConvertCommand    setEnabled: YES];
  465.     [NeXT2CRLFConvertCommand    setEnabled: YES];
  466.     [ConvertCommands    setEnabled: YES];
  467.     //
  468.     return self;
  469. }
  470.  
  471.  
  472.  
  473. @end
  474.  
  475.